package com.csun.cmny.provider.utils;

import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.quartz.*;
import org.quartz.impl.triggers.CronTriggerImpl;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * @author chenzheng
 * @description:关于定时任务的公共方法
 * @date 2019/8/23 17:12
 */
@Slf4j
public class CronUtil {


    /**
     * 获取cron表达式上次执行时间
     *
     * @param cron
     * @return
     */
    public static Date getLastTriggerTime(String cron) {
        if (!CronExpression.isValidExpression(cron)) {
            return null;
        }
        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity("Caclulate Date").withSchedule(CronScheduleBuilder.cronSchedule(cron)).build();
        Date time0 = trigger.getStartTime();
        Date time1 = trigger.getFireTimeAfter(time0);
        Date time2 = trigger.getFireTimeAfter(time1);
        Date time3 = trigger.getFireTimeAfter(time2);
        long l = time1.getTime() - (time3.getTime() - time2.getTime());
        Date date = new Date(l);
        return date;
    }

    @Test
    public void main() {
        String cron = "0 0 0-8 * * ?";
        Date date = getLastTriggerTime(cron);
        System.out.println("date = " + date);
    }

    /**
     * 获取cron表达式下次执行时间
     *
     * @param cron
     * @return
     */
    public static Date getNextTriggerTime(String cron) {
        if (!CronExpression.isValidExpression(cron)) {
            return null;
        }
        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity("Caclulate Date").withSchedule(CronScheduleBuilder.cronSchedule(cron)).build();
        Date time0 = trigger.getStartTime();
        Date time1 = trigger.getFireTimeAfter(time0);
        return time1;
    }

    public static boolean isValidExpression(final String cronExpression) {

        CronTriggerImpl trigger = new CronTriggerImpl();

        try {
            trigger.setCronExpression(cronExpression);
            Date date = trigger.computeFirstFireTime(null);
            return date != null && date.after(new Date());
        } catch (Exception e) {
            log.error("valid cron expression error: {}", e);
        }

        return false;
    }

    public static List<Date> getNextExecTime(String cronExpression, Integer times) {

        CronTriggerImpl cronTriggerImpl = new CronTriggerImpl();

        try {
            cronTriggerImpl.setCronExpression(cronExpression);
        } catch(ParseException e) {
            e.printStackTrace();
        }
        // 这个是重点，一行代码搞定
        return TriggerUtils.computeFireTimes(cronTriggerImpl, null, times);
    }

    public static List<Date> getNextExecTimeOfMonthWithDate(String cronExpression, Date date) {

        java.util.Calendar calendar = java.util.Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(java.util.Calendar.MONTH, -1);
        Date from = calendar.getTime();
        calendar.add(Calendar.MONTH, 3);
        Date to = calendar.getTime();

        CronTriggerImpl cronTriggerImpl = new CronTriggerImpl();
        try {
            cronTriggerImpl.setCronExpression(cronExpression);
        } catch (Exception e) {
            e.printStackTrace();
        }
        List<Date> dateList = TriggerUtils.computeFireTimesBetween(cronTriggerImpl, null, from, to);

        String str_date = com.csun.cmny.util.DateUtil.dateToStr(date);
        Date last_date = new Date();
        Date next_date = new Date();
        for (int i = 0; i < dateList.size() - 1; i++) {
            last_date = dateList.get(i);
            next_date = dateList.get(i + 1);
            String l = com.csun.cmny.util.DateUtil.dateToStr(last_date);
            String n = com.csun.cmny.util.DateUtil.dateToStr(next_date);
            if (str_date.compareTo(l) >=0 && str_date.compareTo(n) < 0) {
                break;
            }
        }

        List<Date> list = Lists.newArrayList();
        list.add(last_date);
        list.add(next_date);

        return list;
    }

    public static boolean isMonthCycle(String cronExpression) {

        boolean isMonthCycle = true;
        int days_month, days_cycle;
        List<Date> dateList = getNextExecTime(cronExpression, 13);
        for (int i = 1; i < dateList.size(); i++) {
            days_cycle = DateUtil.differentDays(dateList.get(i - 1), dateList.get(i));
            days_month = DateUtil.getDaysOfMonth(dateList.get(i - 1));
            if (days_cycle != days_month) {
                isMonthCycle = false;
                break;
            }
        }

        return isMonthCycle;
    }
}


